home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr49 / 262_01.zip / DEBUG.C < prev    next >
Text File  |  1993-04-14  |  28KB  |  873 lines

  1. /***************************************************************
  2.  *           An Interactive Debugger for Q/C                   *
  3.  *                                                             *
  4.  *                 by Robert Ramey                             *
  5.  *                 October    1984                             *
  6.  ***************************************************************/
  7.  
  8. #define MAXLINE 81  /*maximum line of data display format */
  9. #define MAXARGS 12  /*maximum number of arguments of a function */
  10.             /*to be displayed.  note:floats and longs   */
  11.             /*count as two arguments                    */
  12. #define MAXDEPTH 24 /*maximum number of breakpoints in stack   */
  13. #define INSTWIDTH 3 /*width of "call debug" instruction */
  14. #define MAXCOMDEPTH 4   /*maximum depth of inclusion of *.DBG files */
  15. #define APRXSYMBOLS 100 /*approx number of symbols to be defined */
  16. #define SYMSIZE 6   /*size of a symbol */
  17.  
  18. typedef int boolean;
  19. typedef char *ADDRESS;  /*This machine addresses to the byte */
  20.  
  21. static boolean trace = 0;   /*trace toggle*/
  22. #define dataseg (&trace) /*assumes trace is first data symbol */
  23.  
  24. #include <stdio.h>
  25. #include "symdef.h" /*definitions for symbol table routines */
  26.  
  27. static
  28. FILE *fp[MAXCOMDEPTH];  /*stack of included command files */
  29.         /*file pointer for terminal input */
  30. static
  31. int bcnt = 0,   /*number of breakpoints to be skipped */
  32.     depth = 0,  /*number of currently pending breakpoints */
  33.     fpdepth = 0;    /*level of command file inclusion */
  34. static
  35. SYMBOLTABLE *symtbl;    /*table of symbols and data */
  36.  
  37. static
  38. char *fptr, format[MAXLINE];    /*format line */
  39.  
  40. typedef struct symtbl_entry {
  41.     struct symtbl_entry *slnxt, /*next symbol in set/reset list*/
  42.         *slprv, /*previous symbol in set/reset list*/
  43.         *slalpha; /*next symbol in alphabetic list */
  44.     ADDRESS address; /*address of symbol according to *.sym */
  45.     char *symbol,   /*pointer to symbol itself */
  46.         *ptype, /*pointer to format of data or result */
  47.         *arg_format, /*pointer to format of arguments */
  48.             /*(null for data segment items */
  49.         saved_inst[INSTWIDTH + sizeof(int *)],
  50.         /*when break point is set, first instructions*/
  51.         /*are stored here and replaced with call to trap */
  52.         /*followed by address of this structure */
  53.         state;
  54.         /*bit 0 indicates if break point set or not */
  55.         /*bit 1 indicates if break point pending or not*/
  56.     } SYMTBL_ENTRY;
  57. #define PENDING 2
  58. #define SET 1
  59.  
  60. static
  61. SYMTBL_ENTRY *entrylist = NULL, /*list of set breakpoints */
  62.     *pendlist = NULL,   /*list of pending breakpoints */
  63.     *alphafirst = NULL, /*alphabetic list of symbols */
  64.     *alphalast = NULL;  /*last symbol loaded */
  65.  
  66. static
  67. struct {        /* special stack for active breakpoints */
  68.     ADDRESS return_address; /* address of calling function */
  69.     ADDRESS *sp;
  70.     SYMTBL_ENTRY *stdata;   /* currently active break point*/
  71.     } bpstack[MAXDEPTH];
  72.  
  73. char *getfmt();
  74. SYMTBL_ENTRY *dactall();
  75. SYMBOLENTRY *getsym();
  76. void resume();
  77.  
  78. /***************************************************************
  79. setup - this subroutine should be called at the beginning of
  80. program execution.  It permits initial use of commands to load
  81. symbol tables and set breakpoints.
  82. ***************************************************************/
  83. setup()
  84. {
  85.     /* setup symbol table */
  86.     if(!(symtbl = symmk(sizeof(SYMTBL_ENTRY), APRXSYMBOLS))){
  87.         fputs("Not enough memory for symbol table\n", stderr);
  88.         exit(1);
  89.     }
  90.     /* open file to be used for debugger commands */
  91.     fp[0] = fopen("con:", "r");
  92.  
  93.     ldtbl("DEBUG.SYM"); /*load symbol file */
  94.     comand();       /*accept initial debugger commands */
  95.  
  96.     actall();/* activate entry point traps and continue */
  97.  
  98. }
  99. /**************************************************************
  100. trap - when a subroutine is entered this function is called.
  101. Here is where program flow is traced and if a breakpoint encounterd
  102. execution is suspended in order to process debugger commands
  103. **************************************************************/
  104. static void
  105. trap(caller)
  106. ADDRESS caller;
  107. {
  108.     ADDRESS entrypt;
  109.     SYMTBL_ENTRY *stdata;
  110.     boolean all;
  111.  
  112.     /* retieve entry point address.  assumes that the subroutine */
  113.     /* entry point has been replaced with a "call trap" instruc- */
  114.     /* -tion there leaving on the stack a return address just */
  115.     /* beyond the entry point */
  116.     entrypt = *(&caller - 1) - INSTWIDTH;
  117.  
  118.     /* following the "call trap" instruction at the subroutine */
  119.     /* entry the address of the symbol data structure is stored */
  120.     stdata = *(int *)(entrypt + INSTWIDTH);
  121.  
  122.     if(depth == MAXDEPTH)
  123.         fputs("Too many pending breakpoints\n",stderr);
  124.     else{
  125.         /* store information on encounterd breakpoint on */
  126.         /* stack of currently pending subroutines */
  127.         bpstack[depth].stdata = stdata;
  128.         bpstack[depth].return_address = caller;
  129.         bpstack[depth].sp = &caller + 1;
  130.  
  131.         /* restore original contents to the entry point to */
  132.         /* permit normal execution of subroutine to proceed */
  133.         /* note: this means the tracing will not show */
  134.         /* recurrsive subroutine calls */
  135.         dactbp(stdata);
  136.         /* remove entry point from list to be activated */
  137.         relink(stdata, &pendlist);
  138.         stdata->state ^= PENDING;
  139.  
  140.         /* replace address of caller with address of resume */
  141.         /* so that resume will gain control when subroutine */
  142.         /* returns.  This will permit resume to display */
  143.         /* return value of subroutine */
  144.         caller = resume; /* return for interrupted routine */
  145.  
  146.         /* increment index into stack of pending entry points*/
  147.         ++depth;
  148.     }
  149.  
  150.     if((!bcnt && stdata->state & SET) || trace){
  151.         /* deactivate all entry point traps to permit */
  152.         /* normal use of library subroutines by the debugger */
  153.         dactall();
  154.  
  155.         /* display subroutine name and its arguments */
  156.         /* assumes that arguments have been pushed on to */
  157.         /* stack before calling trapped subroutine */
  158.         dentry(&caller+1,stdata);
  159.     }
  160.     else
  161.         all = FALSE;
  162.  
  163.     if(stdata->state & SET) /*if is a a break point */
  164.         if(!bcnt)
  165.             comand();
  166.         else
  167.             --bcnt;
  168.  
  169.     /* if necessary reactivate all entry point traps */
  170.     if(all) actall();
  171.     
  172.     /* continue execution by loading entry point on top of */
  173.     /* current return address */
  174.     *(&caller - 1) = entrypt;   /* return to break point */
  175. }
  176. /****************************************************************
  177. resume - recieves control when a trapped subroutine returns.
  178. The object of this is to undo the changes done in trap and
  179. permit display of value returned.
  180. *****************************************************************/
  181. static void
  182. resume(){
  183. #asm
  184.     push    af  ;save z flag
  185.     push    hl  ;save return value on stack
  186. #endasm
  187.     if(trace){
  188.         /* display value returned by subroutine */
  189.         dactall();
  190.         dexit(bpstack[depth-1].stdata);
  191.         actall();
  192.     }
  193.     /* reactivate trapping of this subrouine */
  194.     actbp(bpstack[--depth].stdata);
  195.     relink(bpstack[depth].stdata, &entrylist);
  196.     bpstack[depth].stdata->state ^= PENDING;
  197.     bpstack[depth].return_address++; /*leave return address in HL*/
  198. #asm
  199.     pop de  ;recover subroutine return value
  200.     pop af  ;recover flags
  201.     push    de
  202.     ex  (sp),hl ;leave returned original returned value in HL
  203.             ;leave original return address on stack
  204. #endasm
  205. }
  206. /****************************************************************
  207. actall - activate trapping of all subroutine calls for all entry
  208. points in the entry point list.
  209. *****************************************************************/
  210. static void
  211. actall()
  212. {
  213.     SYMTBL_ENTRY *stdata;
  214.     for(stdata = entrylist;stdata;stdata = stdata->slnxt)
  215.         actbp(stdata);
  216. }
  217. /*****************************************************************
  218. dactall - dactivate trapping of all subroutines in the list of
  219. entry points.  This is necessary in order to permit the debugger
  220. program to use library routines without trapping itself.
  221. ******************************************************************/
  222. static
  223. SYMTBL_ENTRY *
  224. dactall(entrypt)
  225. ADDRESS entrypt;
  226. {
  227.     SYMTBL_ENTRY *stdata;
  228.     for(stdata = entrylist;stdata;stdata = stdata->slnxt){
  229.         dactbp(stdata);
  230.     }
  231. }
  232. /******************************************************************
  233. dentry - display entry point with arguments on entering function 
  234. ******************************************************************/
  235. static void
  236. dentry(stackpt, stdata)
  237. ADDRESS stackpt;
  238. SYMTBL_ENTRY *stdata;
  239. {
  240.     char *p;
  241.     /* set up string for format of arguments */
  242.     if(!stdata->ptype)
  243.         /* if no format string has been specified */
  244.         p = "";
  245.     else
  246.         p = stdata->arg_format;
  247.     ddata(">%s", stackpt, p, stdata->symbol, 2);
  248. }
  249. /***************************************************************
  250. dexit - display breakpoint with return value on exit of function
  251. ****************************************************************/
  252. static void
  253. dexit(stdata,retval)
  254. SYMTBL_ENTRY *stdata;
  255. int retval;
  256. {
  257.     char c, *a, *p, *t;
  258.     long longval;
  259.     int *aptr;
  260.  
  261.     /* isolate first part of format string to be used to display */
  262.     /* argument. */
  263.     if(!stdata->ptype){
  264.         p = "";
  265.         a = &c;
  266.     }
  267.     else{
  268.         p = stdata->ptype;
  269.         a = stdata->arg_format;
  270.     }
  271.     c = *a;
  272.     *a = '\0';
  273.  
  274.     /* if a long is returned, get long value from special stack */
  275.     /* check to see if prototype is long or float */
  276.     for(t = p;*t != '%' && *t != NULL;++t);
  277.     if(*t){
  278.         switch(*++t){
  279.         default:
  280.             aptr = &retval;
  281.             break;
  282.         case 'l':
  283.         case 'L':
  284.         case 'f':
  285.         case 'F':
  286.             /* leave address of long value in HL */
  287.             aptr = &longval;
  288. #asm
  289.             call    ?save32;/* move TOS to longval */
  290. #endasm
  291.         }
  292.     }
  293.     ddata("<%s = ", aptr, p, stdata->symbol, 2);
  294.     *a = c;
  295. }
  296. /*************************************************************
  297. ddata - display data from memory
  298. **************************************************************/
  299. static void
  300. ddata(idstr, data_address, ptype, symbol, charsize)
  301. char    *idstr, /*address of string identifying symbol */
  302.     *symbol, /*address of symbol to be displayed */
  303.     *ptype; /*points to format of display */
  304. int data_address[],
  305.         /*points to first memory location to be displayed */
  306.     charsize;   /*size of character variable */
  307.         /*1 if in memory, 2 if on a stack */
  308. {
  309.     int arg[MAXARGS];   /*arguments to be displayed */
  310.         /*note: must be first for fprint (below) to function */
  311.     int i;
  312.     
  313.     /*indent display according to depth of call stack */
  314.     for(i = 0;i < depth;++i) format[i] = ' ';
  315.     fptr = strmov(format+depth,idstr);
  316.  
  317.     /*first item displayed is the symbol it self */
  318.     arg[0] = symbol;
  319.  
  320.     /*fill rest of arg array */
  321.     farg(arg + 1, data_address, &ptype, charsize);
  322.  
  323.     fptr = strmov(fptr, "\n");
  324.     fprintf(stderr,format); /*format is format string. */
  325.         /*arguments are on top of stack already */
  326.         /*because arg[] is first local variable */
  327. }
  328. /***************************************************************
  329. farg - fill in array of arguments to be passed to fprintf.
  330. Leave modifyed format string in static variable format.
  331. **************************************************************/
  332. static void
  333. farg(arg, data_address, ptype, charsize)
  334. int arg[],  /* array into which arguments are to be loaded */
  335.     data_address[], /* array which currently holds arguments */
  336.     charsize; /* size of objects to be displayed with %c */
  337.         /* These are 1 if character is in memory, */
  338.         /* 2 if character has been pushed onto stack */
  339. char    **ptype; /* pointer to address of format string to be used */
  340.  
  341. {
  342.     int icount, *targ;
  343.     char c, state;
  344.     state = ' ';
  345.     icount = 0;
  346.     while(c = *(*ptype)++){
  347.         switch(state){
  348.         case ' ':
  349.             switch(c){
  350.             default:
  351.                 icount = 0;
  352.                 break;
  353.             case '%':
  354.                 state = '%';
  355.                 break;
  356.             case '*':
  357.                 state = '*';
  358.                 icount = 1;
  359.                 break;
  360.             case '(':
  361.                 *fptr++ = c;
  362.                 farg(arg,data_address,ptype,charsize);
  363.                 c = ')';
  364.                 break;
  365.             case ')':
  366.                 return;
  367.             case '\"':
  368.                 state = '\"';
  369.                 break;
  370.             }
  371.             break;
  372.         case '\"':
  373.             if(c == '\"')
  374.                 state = ' ';
  375.             break;
  376.         case '*':
  377.             switch(c){
  378.             case '*':
  379.                 ++icount;
  380.                 break;
  381.             case '%':
  382.                 state = '%';
  383.                 break;
  384.             case '(':
  385.                 fptr -= icount;
  386.                 targ = data_address++;
  387.                 while(icount--)
  388.                     targ = *targ;
  389.                 *fptr++ = '(';
  390.                 farg(arg,targ,ptype,1);
  391.                 c = ')';
  392.             default:
  393.                 state = ' ';
  394.                 icount = 0;
  395.                 break;
  396.             }
  397.             break;
  398.         case '%':
  399.             state = ' ';
  400.             if(c == '%' || c == ')' || c == '('){
  401.                 fptr -= icount;
  402.                 break;
  403.             }
  404.             if(c == 'c' && charsize == 1 && icount == 0){
  405.                 targ = (char *)data_address;
  406.                 data_address =
  407.                 (int *)(1 + (char *)data_address);
  408.             }
  409.             else{
  410.                 targ = data_address++;
  411.                 while(icount--)
  412.                     targ = *targ;
  413.             }
  414.             if(c == 'c' && charsize == 1)
  415.                 *arg++ = *(char *)targ;
  416.             else
  417.             if(c == 'f' || c == 'l'){
  418.                 /* longs and floats use two words */
  419.                 *arg++ = *targ++;
  420.                 *arg++ = *targ;
  421.             }
  422.             else
  423.                 /* everything else uses one word */
  424.                 *arg++ = *targ;
  425.         }
  426.         *fptr++ = c;
  427.     }
  428. }
  429. /*****************************************************************
  430. comand - read and process command from keyboard or file
  431. *****************************************************************/
  432. static void
  433. comand()
  434. {
  435.     SYMBOLENTRY *ste;
  436.     SYMTBL_ENTRY *stdata;
  437.     char c, *fstart, *fend;
  438.     int addr, i;
  439.     FILE *fl;
  440.  
  441.     for(;;){    /* main command loop */
  442.  
  443.     putc('*',stderr);   /* prompt screen for input */
  444.  
  445.     /* get line from current input file */
  446.     while(!fgets(format,MAXLINE - 1,fp[fpdepth])){
  447.         if(!fpdepth) return;
  448.         --fpdepth;
  449.         continue;
  450.     }
  451.     if(!isatty(fileno(fp[fpdepth])))/*if input not from keyboard */
  452.         fputs(format,stderr);   /*echo input to screen */
  453.  
  454.     fstart = format;
  455.     while(isspace(*++fstart));  /*skip leading spaces */
  456.     switch(tolower(format[0])){
  457.     case 'b':/*toggle breakpoint */
  458.         /*b<breakpoint symbol> [<format string>]*/
  459.         /*b without arg toggles all breakpoints */
  460.         if(!*fstart){   /*no arguments*/
  461.             for(stdata = pendlist;stdata;
  462.                 stdata = stdata->slnxt)
  463.                 stdata->state ^= SET;
  464.             for(stdata = entrylist;stdata;
  465.                 stdata = stdata->slnxt)
  466.                 stdata->state ^= SET;
  467.             break;
  468.         }
  469.  
  470.         /* with a symbol */
  471.         if(!(ste = getsym(&fstart))){
  472.             serr();
  473.             break;
  474.         }
  475.         stdata = (SYMTBL_ENTRY *)symdat(symtbl,ste);
  476.         if(stdata->address < dataseg){
  477.             stdata->state ^= SET;
  478.             getfmt(stdata,fstart);  /* reset format */
  479.         }
  480.         else
  481.             fputs("Symbol not in code segment\n",stderr);
  482.         break;
  483.     case 'f':/*specify format string for subroutine arguments or */
  484.         /*external variable */
  485.         /*f <symbol> <format string> */
  486.         if(!(ste = getsym(&fstart))){
  487.             serr();
  488.             break;
  489.         }
  490.         stdata = (SYMTBL_ENTRY *)symdat(symtbl,ste);
  491.         if(!*fstart){
  492.             /* return space used by current format string*/
  493.             if(stdata->ptype){
  494.                 free(stdata->ptype);
  495.                 stdata->ptype = NULL;
  496.             }
  497.         }
  498.         else
  499.             /* set new format string from rest of command*/
  500.             getfmt(stdata, fstart);
  501.         break;
  502.     case 'g':/*continue execution skipping n breakpoints*/
  503.         /*g [<number of break points to be displayed>] */
  504.         i = sscanf(fstart, "%d", &bcnt);
  505.         if(i == EOF) bcnt = 0;
  506.         return;
  507.     case 't':/*toggle trace mode */
  508.         trace = 1 - trace;
  509.         fputs("trace o", stderr);
  510.         fputs(trace ? "n\n" : "ff\n", stderr);
  511.         break;
  512.     case 'c':/*process debug commands from a disk file */
  513.         /*c <filename> */
  514.         if(++fpdepth == MAXCOMDEPTH){   /* nested too deep? */
  515.             --fpdepth;
  516.             fputs("Comand file nested to deeply\n",stderr);
  517.             break;
  518.         }
  519.         /* get filename from rest of command line */
  520.         fname(fstart, ".DBG");
  521.         if(!(fp[fpdepth] = fopen(fstart, "r"))){
  522.             fprintf(stderr,
  523.             "Could not open file %s\n",fstart);
  524.             --fpdepth;
  525.         }
  526.         break;
  527.     case 'l':/*load file of symbols generated by link */
  528.         /*l <filename> */
  529.         /* get file name from rest of command line */
  530.         fname(fstart, ".SYM");
  531.         ldtbl(fstart);
  532.         break;
  533.     case 'd':/*display global variabk */
  534.         /*d <symbol name> */
  535.         /*d without args displays all external variables in*/
  536.         /* the data segment */
  537.         if(!*fstart){
  538.             for(stdata = alphafirst; stdata;
  539.                  stdata = stdata->slalpha)
  540.                 ddata("%s ",stdata->address,
  541.                     stdata->ptype, ste, 1);
  542.             break;
  543.         }
  544.         if(!(ste = getsym(&fstart))){
  545.             serr();
  546.             break;
  547.         }
  548.         stdata = (SYMTBL_ENTRY *)symdat(symtbl, ste);
  549.         ddata("%s=",stdata->address,
  550.         getfmt(stdata, fstart),ste,1);
  551.         break;
  552.     case 'w':/*display argument stack */
  553.         i = depth;
  554.         for(depth = 0;depth < i;++depth){
  555.         dentry(bpstack[depth].sp,bpstack[depth].stdata);
  556.         }
  557.         depth = i;
  558.         break;
  559.     case 's':/*display or set symbol table entry */
  560.         /*s without arguments display all symbols */
  561.         /*s <symbol> displays symbol and address */
  562.         /*s <symbol> <hex> creates symbol with given address*/
  563.         if(!*fstart){
  564.             for(stdata = alphafirst; stdata;
  565.                  stdata = stdata->slalpha)
  566.                 dsymtbl(stdata);
  567.             break;
  568.         }
  569.         fend = fstart;
  570.         ste = getsym(&fend);
  571.         i = sscanf(fend, "%4x", &addr);
  572.         if(i == EOF) i = 0;
  573.         if(!i && ste)
  574.             dsymtbl((SYMTBL_ENTRY *)symdat(symtbl,ste));
  575.         else if(!i && !ste)
  576.             serr();
  577.         else if(i && ste){
  578.             stdata = (SYMTBL_ENTRY *)symdat(symtbl, ste);
  579.             stdata->address = addr;
  580.             dsymtbl(stdata);
  581.         }
  582.         else
  583.             loadsym(fstart,addr);
  584.         break;
  585.     default:
  586.         fputs("invalid debugger command\n", stderr);
  587.     case '\n':;
  588.     /*null command*/
  589.     }
  590.     }
  591. }
  592. /*************************************************************
  593. dsymtbl - display data for one symbol table entry
  594. **************************************************************/
  595. static void
  596. dsymtbl(stdata)
  597. SYMTBL_ENTRY *stdata;
  598. {
  599.     char c;
  600.     c = (stdata->state & SET) ? 'B' : ' ';
  601.     fprintf(stderr,
  602.         stdata->ptype ?
  603.              "%c %x\t%s\t%s\n" : "%c %x\t%s\n",
  604.         c, stdata->address, stdata->symbol, stdata->ptype);
  605. }
  606. /**************************************************************
  607. relink - remove entry point from its current list and link on 
  608. to head of a new list.
  609. **************************************************************/
  610. static void
  611. relink(stdata, list)
  612. SYMTBL_ENTRY *stdata, **list;
  613. {
  614.     /*delink from current breakpoint list */
  615.     if(stdata->slnxt)
  616.         stdata->slnxt->slprv = stdata->slprv;
  617.     stdata->slprv->slnxt = stdata->slnxt;
  618.  
  619.     /*link into requested breakpoint list*/
  620.     if(*list)
  621.         (*list)->slprv = stdata;
  622.     stdata->slnxt = *list;
  623.     stdata->slprv = list;
  624.     *list = stdata;
  625. }
  626. /***************************************************************
  627. actbp - activate trapping of a given entry point.
  628. ***************************************************************/
  629. static void
  630. actbp(stdata)
  631. SYMTBL_ENTRY *stdata;
  632. {
  633.     char *j;
  634.     /*load with "call trap" instruction */
  635.     j = stdata->address;
  636.     j[0] = 0xCD;    /* Z-80 call */
  637.     j[1] = trap;        /* "trap" address */
  638.     j[2] = trap >> 8;
  639.  
  640.     /*followed by address of corresponding symbol table entry */
  641.     *((SYMTBL_ENTRY **)(j + INSTWIDTH)) = stdata;
  642. }
  643. /****************************************************************
  644. dactbp - deactivate trapping of a given entry point.
  645. *****************************************************************/
  646. /* dactbp - deactivate a breakpoint */
  647. static void
  648. dactbp(stdata)
  649. SYMTBL_ENTRY *stdata;
  650. {
  651.     /* restore original contents of breakpoint address */
  652.     memcpy(stdata->address,stdata->saved_inst,
  653.         INSTWIDTH + sizeof(SYMTBL_ENTRY *));
  654. }
  655. /****************************************************************
  656. fname - check and build name of file
  657. ****************************************************************/
  658. static void
  659. fname(prfix,sufix)
  660. char *prfix, *sufix;
  661. {
  662.     char c;
  663.     --prfix;
  664.     while((c = *++prfix) == ':' || isalnum(c));
  665.     if(*prfix != '.')
  666.         strmov(prfix, sufix);
  667.     else{
  668.         while(isalnum(*++prfix));
  669.         *prfix = '\0';
  670.     }
  671. }
  672. /*****************************************************************
  673. getsym - get symbol from string. return pointer to next non
  674. blank character.
  675. *****************************************************************/
  676. static SYMBOLENTRY *
  677. getsym(text)
  678. char **text;
  679. {
  680.     char *i, *j;
  681.     int k;
  682.     if(!*text){
  683.         fputs("Comand needs symbol\n",stderr);
  684.         return NULL;
  685.     }
  686.     for(j = *text,k = 0;
  687.         *j && (!isspace(*j)) && (k < SYMSIZE);
  688.         ++j,++k);
  689.     i = j;
  690.     while(!isspace(*j)) ++j;    /*skip rest of current word */
  691.     while(isspace(*j)) ++j;     /*skip to next word */
  692.  
  693.     if(*(i - 1) == '?') --i;    /*strip off trailing '?'*/
  694.     *i = '\0';
  695.     strlwr(*text);
  696.     i = *text;
  697.     *text = j;
  698.     return symlkup(symtbl, i);
  699. }
  700. /****************************************************************
  701. serr - Symbol not defined message
  702. *****************************************************************/
  703. static void
  704. serr()
  705. {
  706.     fputs("Symbol not defined\n", stderr);
  707. }
  708. /****************************************************************
  709. getfmt - get and/or store format to be displayed
  710. *****************************************************************/
  711. static char *
  712. getfmt(stdata, fstart)
  713. SYMTBL_ENTRY *stdata;
  714. char *fstart;
  715. {
  716.     char *p;
  717.     if(p = strchr(fstart, '\n'))
  718.         *p = NULL;
  719.     if(*fstart) {
  720.         p = stdata->ptype;
  721.         if(p)
  722.             free(p);
  723.         stdata->ptype =
  724.         p = malloc(1 + strlen(fstart));
  725.         strmov(p,fstart);
  726.         if(stdata->address < dataseg)
  727.             initp(stdata);
  728.     }
  729.     else if(!(p = stdata->ptype))
  730.         p = " %x";
  731.     return p;
  732. }
  733. /****************************************************************
  734. initp - initialize format pointers for a code segment symbol
  735. *****************************************************************/
  736. static void
  737. initp(stdata)
  738. SYMTBL_ENTRY *stdata;
  739. {
  740.     int arg, level;
  741.     char *p;
  742.     p = stdata->ptype;
  743.     /*separate first % as format for return value */
  744.     arg = FALSE;
  745.     level = 0;
  746.     for(;;){
  747.         switch(*p++){
  748.         case NULL:
  749.         case '\n':
  750.             break;
  751.         case '(':
  752.             ++level;
  753.             continue;
  754.         case ')':
  755.             --level;
  756.             continue;
  757.         case '%':
  758.             if(arg && !level)
  759.                 break;
  760.             else
  761.                 arg = TRUE;
  762.             continue;
  763.         case '\t':
  764.         case ' ':
  765.             if(arg && !level){
  766.                 --p;
  767.                 break;
  768.             }
  769.             continue;
  770.         default:
  771.             continue;
  772.         }
  773.         break;
  774.     }
  775.     stdata->arg_format = p;
  776. }
  777. /************************************************************
  778. ldtbl - load a symbol file from disk given its name
  779. ************************************************************/
  780. static void
  781. ldtbl(fname)
  782. char *fname;
  783. {
  784.     FILE *fl;
  785.     ADDRESS addr;
  786.     SYMBOLENTRY *ste;
  787.     if(!(fl = fopen(fname, "r"))){
  788.         fprintf(stderr,
  789.         "Could not open file %s\n",fname);
  790.         return;
  791.     }
  792.     while(fscanf(fl,"%x %s",&addr,format) == 2){
  793.         /* symbols starting with ? are generally*/
  794.         /* not interesting in programs compiled with */
  795.         /* QC.  I have chosen to exclude them in */
  796.         /* to reduce size of symbol table */
  797.         if(format[0] == '?')
  798.             continue; /*skip internal symbols */
  799.         /* QC changes initial _ to @ to avoid */
  800.         /* error messages from linker */
  801.         if(format[0] == '@')
  802.             format[0] = '_';
  803.         fptr = format;
  804.         if(ste = getsym(&fptr)){
  805.             fprintf(stderr,
  806.                 "%s already loaded\n",ste);
  807.             continue;
  808.         }
  809.         if(!loadsym(format, addr))
  810.             break;
  811.     }
  812.     fclose(fl);
  813. }
  814. /****************************************************************
  815. loadsym - add a new symbol to symbol table
  816. *****************************************************************/
  817. static int
  818. loadsym(symbol, addr)
  819. char *symbol;
  820. ADDRESS addr;
  821. {
  822.     SYMBOLENTRY *ste;
  823.     SYMTBL_ENTRY *stdata;
  824.  
  825.     if(!(ste = symadd(symtbl,symbol))){
  826.         fputs("Can't load any more symbols\n",
  827.         stderr);
  828.         return FALSE;
  829.     }
  830.     stdata = (SYMTBL_ENTRY *)symdat(symtbl, ste);
  831.     stdata->address = addr;
  832.     stdata->state =
  833.     stdata->ptype = NULL;
  834.     stdata->symbol = (char *)ste;
  835.     
  836.     /*if in code segment add to entrylist */
  837.     if(addr < dataseg){
  838.         /*store in symbol table original contents of entry pt*/
  839.         memcpy(stdata->saved_inst,
  840.             addr,
  841.             INSTWIDTH + sizeof(SYMTBL_ENTRY *));
  842.         /*link into list of entry points*/
  843.         if(entrylist)
  844.             entrylist->slprv = stdata;
  845.         stdata->slnxt = entrylist;
  846.         entrylist = stdata;
  847.         stdata->slprv = &entrylist;
  848.     }
  849.     
  850.     /*add to alphabetic list */
  851.     if(!alphafirst)
  852.         alphalast =
  853.         alphafirst = stdata;
  854.     else
  855.         alphalast->slalpha = stdata;
  856.     alphalast = stdata;
  857.     stdata->slalpha = NULL;
  858.     return TRUE;
  859. }
  860. /*******************************************************************
  861. memcpy - copy n characters to destination from source
  862. *********************************************************************/
  863. static void
  864. memcpy(dest, source, count)
  865. char *dest, *source;
  866. int count;
  867. {
  868.     while(count--) *dest++ = *source++;
  869. }
  870. if(!alphafirst)
  871.         alphalast =
  872.         alphafirst = stdata;
  873.     e